/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
//
//  filename: 	LaborPlaneBoundedVolume.h
//  created:	10:03 8/6/2006
//  author:		rock.mao 
//	Description:
//
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __LABOR_PLANEBOUNDEDVOLUME_H__
#define __LABOR_PLANEBOUNDEDVOLUME_H__

#include "LaborPrerequisites.h"
#include "LaborMathInclude.h"

#include "LaborCoreDef.h"
NAMESPACE_LABOR3D_BEGIN


/** Represents a convex volume bounded by planes.
*/
class LABORCORE_API CLPlaneBoundedVolume
{
public:
	/// Publicly accessible plane list, you can modify this direct
	std::vector<CLPlane> planes;
	CLPlane::Side outside;

	CLPlaneBoundedVolume() :outside(CLPlane::NEGATIVE_SIDE) {}
	/** Constructor, determines which side is deemed to be 'outside' */
	CLPlaneBoundedVolume(CLPlane::Side theOutside) 
		: outside(theOutside) {}

	/** Intersection test with AABB
	@remarks May return false positives but will never miss an intersection.
	*/
	inline bool intersects(const CLAABB& box) const
	{
		if( !box.isValid() )
			return false;

		// If all points are on outside of any plane, we fail
		CLPoint points[8];
		box.computePoints( points );

		std::vector<CLPlane>::const_iterator i, iend;
		iend = planes.end();
		for (i = planes.begin(); i != iend; ++i)
		{
			const CLPlane& plane = *i;

			// Test which side of the plane the corners are
			// Intersection fails when at all corners are on the
			// outside of one plane
			bool splittingPlane = true;
			for (int corner = 0; corner < 8; ++corner)
			{
				if (plane.getSide(points[corner]) != outside)
				{
					// this point is on the wrong side
					splittingPlane = false;
					break;
				}
			}
			if (splittingPlane)
			{
				// Found a splitting plane therefore return not intersecting
				return false;
			}
		}

		// couldn't find a splitting plane, assume intersecting
		return true;

	}
	/** Intersection test with CLSphere
	@remarks May return false positives but will never miss an intersection.
	*/
	inline bool intersects(const CLSphere& sphere) const
	{
		std::vector<CLPlane>::const_iterator i, iend;
		iend = planes.end();
		for (i = planes.begin(); i != iend; ++i)
		{
			const CLPlane& plane = *i;

			// Test which side of the plane the sphere is
			
			float d = plane.distance(sphere.getCenter());
			// Negate d if planes point inwards
			if (outside == CLPlane::NEGATIVE_SIDE) d = -d;

			if ( (d - sphere.getRadius()) > 0)
				return false;
		}

		return true;

	}

	/** Intersection test with a CLRay
	@returns std::pair of hit (bool) and distance
	@remarks May return false positives but will never miss an intersection.
	*/
	inline std::pair<bool, float> intersects(const CLRay& ray)
	{
		return intersectEx(ray, planes, outside == CLPlane::POSITIVE_SIDE);
	}

};

typedef std::vector<CLPlaneBoundedVolume> PlaneBoundedVolumeList;


NAMESPACE_LABOR3D_END

#endif